import * as ts from "typescript";
import * as vscode from "vscode";

/** unicode cjk 中日韩文 范围 */
const DOUBLE_BYTE_REGEX = /[\u4E00-\u9FFF]/g;

function trimWhiteSpace(
  code: string,
  startPos: vscode.Position,
  endPos: vscode.Position
) {
  const lines = code.split("\n");
  const hasContentLines = [];
  const columnOfLine: any = {};
  for (let i = startPos.line; i <= endPos.line; i++) {
    const line = lines[i];
    let colStart = 0;
    let colEnd = line.length;
    if (i === startPos.line) {
      colStart = startPos.character;
    }
    if (i === endPos.line) {
      colEnd = endPos.character;
    }
    const text = line.slice(colStart, colEnd).trim();
    if (text.length) {
      hasContentLines.push(i);
      /** 如果文字前面，全是空格 */
      if (!colStart) {
        colStart = line.length - (line as any).trimLeft().length;
      }
    }
    columnOfLine[i] = [colStart, colEnd];
  }
  const startLine = Math.min(...hasContentLines);
  const startCol = Math.min(...columnOfLine[startLine]);
  const endLine = Math.max(...hasContentLines);
  const endCol = Math.max(...columnOfLine[endLine]);

  return {
    trimStart: new vscode.Position(startLine, startCol),
    trimEnd: new vscode.Position(endLine, endCol),
  };
}

/**
 * 去掉文件中的注释
 * @param code
 * @param fileName
 */
export function removeFileComment(code: string, fileName: string) {
  const printer: ts.Printer = ts.createPrinter({ removeComments: true });
  const sourceFile: ts.SourceFile = ts.createSourceFile(
    "",
    code,
    ts.ScriptTarget.ES2015,
    true,
    fileName.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS
  );
  return printer.printFile(sourceFile);
}

/**
 * 查找 Ts 文件中的中文
 * @param code
 */

function findTextInTs(code: string, fileName: string) {
  const matches: any[] = [];
  const activeEditor = vscode.window.activeTextEditor;
  const ast = ts.createSourceFile(
    "",
    code,
    ts.ScriptTarget.ES2015,
    true,
    ts.ScriptKind.TSX
  );

  function visit(node: ts.Node) {
    switch (node.kind) {
      case ts.SyntaxKind.StringLiteral: {
        /** 判断 Ts 中的字符串含有中文 */
        const { text } = node as ts.StringLiteral;
        if (text.match(DOUBLE_BYTE_REGEX)) {
          const start = node.getStart();
          const end = node.getEnd();
          /** 加一，减一的原因是，去除引号 */
          const startPos = activeEditor?.document.positionAt(start + 1);
          const endPos = activeEditor?.document.positionAt(end - 1);
          const range = new vscode.Range(
            startPos as vscode.Position,
            endPos as vscode.Position
          );
          matches.push({
            range,
            text,
            isString: true,
          });
        }
        break;
      }
      case ts.SyntaxKind.JsxElement: {
        const { children } = node as ts.JsxElement;

        children.forEach((child) => {
          if (child.kind === ts.SyntaxKind.JsxText) {
            const text = child.getText();
            /** 修复注释含有中文的情况，Angular 文件错误的 Ast 情况 */
            const noCommentText = removeFileComment(text, fileName);

            if (noCommentText.match(DOUBLE_BYTE_REGEX)) {
              const start = child.getStart();
              const end = child.getEnd();
              const startPos = activeEditor?.document.positionAt(start);
              const endPos = activeEditor?.document.positionAt(end);
              const { trimStart, trimEnd } = trimWhiteSpace(
                code,
                startPos as vscode.Position,
                endPos as vscode.Position
              );
              const range = new vscode.Range(trimStart, trimEnd);

              matches.push({
                range,
                text: text.trim(),
                isString: false,
              });
            }
          }
        });
        break;
      }
      case ts.SyntaxKind.TemplateExpression: {
        const { pos, end } = node;
        let templateContent = code.slice(pos, end);
        templateContent = templateContent
          .toString()
          .replace(/\$\{[^\}]+\}/, "");
        if (templateContent.match(DOUBLE_BYTE_REGEX)) {
          const start = node.getStart();
          const end = node.getEnd();
          /** 加一，减一的原因是，去除`号 */
          const startPos = activeEditor?.document.positionAt(start + 1);
          const endPos = activeEditor?.document.positionAt(end - 1);
          const range = new vscode.Range(
            startPos as vscode.Position,
            endPos as vscode.Position
          );
          matches.push({
            range,
            text: code.slice(start + 1, end - 1),
            isString: true,
          });
        }
        break;
      }
      case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
        const { pos, end } = node;
        let templateContent = code.slice(pos, end);
        templateContent = templateContent
          .toString()
          .replace(/\$\{[^\}]+\}/, "");
        if (templateContent.match(DOUBLE_BYTE_REGEX)) {
          const start = node.getStart();
          const end = node.getEnd();
          /** 加一，减一的原因是，去除`号 */
          const startPos = activeEditor?.document.positionAt(start + 1);
          const endPos = activeEditor?.document.positionAt(end - 1);
          const range = new vscode.Range(
            startPos as vscode.Position,
            endPos as vscode.Position
          );
          matches.push({
            range,
            text: code.slice(start + 1, end - 1),
            isString: true,
          });
        }
    }

    ts.forEachChild(node, visit);
  }
  ts.forEachChild(ast, visit);

  return matches;
}

export const getChineseList = (code: string, fileName: string) => {
  return findTextInTs(code, fileName);
};
